﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ThreeByte.ActiveDeck.Config;
using System.Xml.Linq;
using ThreeByte.ActiveDeck.Service;
using System.IO;
using log4net;
using System.Text.RegularExpressions;

namespace ThreeByte.ActiveDeck.AddIn.Config
{
    public class GraphicResourceSerializer
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(GraphicResourceSerializer));
        private static readonly string INDEX_FILE = "index.xml";
        private static XNamespace ns = ServiceConfiguration.NAMESPACE;

        public static readonly XElement EXTERNAL_GRAPHICS_FLAG = new XElement(ns + "ExternalGraphics");

        public string StorePath { get; private set; }

        public GraphicResourceSerializer(string storepath) {
            StorePath = storepath;
        }

        public void SerializeAllResources(CoreConfig config) {
            Dictionary<Guid, GraphicResource> persistentResources = new Dictionary<Guid, GraphicResource>();

            //Iterate over all of the presentation level resources
            foreach(GraphicResource res in config.Graphics) {
                persistentResources[res.ID] = res;
            }
            if(config.Logo != null) {
                persistentResources[config.Logo.ID] = config.Logo;
            }
            if(config.HomePage != null) {
                persistentResources[config.HomePage.ID] = config.HomePage;
            }
            if(config.EndPage != null) {
                persistentResources[config.EndPage.ID] = config.EndPage;
            }

            //Iterate over all of the slides and grab their persistent resources
            foreach(int id in config.SlideIDs) {
                foreach(PageConfig page in config[id].Pages) {
                    foreach(GraphicResource g in page.GetPersistentGraphicResources()) {
                        persistentResources[g.ID] = g;
                    }
                }
            }

            //Find the presentation path, and create a new graphics directory
            ////TODO: Handle empty path?
            //string presentationPath = Config.Presentation.Path;
            //Save all of the graphic resources to files in the directory
            XElement indexNode = new XElement(ServiceConfiguration.NAMESPACE + "Index");
            foreach(Guid g in persistentResources.Keys) {
                GraphicResource res = persistentResources[g];
                string filename = string.Format("{0}\\{1}.{2}", StorePath, res.ID, res.ImageType);
                SaveGraphicResourceToFile(persistentResources[g], filename);
                indexNode.Add(res.GetXmlHeader());
            }

            //Construct an index file
            string indexFilename = string.Format("{0}\\{1}", StorePath, INDEX_FILE);
            indexNode.Save(indexFilename);
        }


        public void PurgeUnindexedFiles() {
            string indexFilename = string.Format("{0}\\{1}", StorePath, INDEX_FILE);
            XElement indexNode = XElement.Load(indexFilename);

            //Get all of the files that should be saved
            HashSet<Guid> indexedGuids = new HashSet<Guid>();
            foreach(XElement g in indexNode.Elements(GraphicResource.XML_NAME)) {
                indexedGuids.Add(Guid.Parse(g.Attribute("ID").Value));
            }

            int filesDeleted = 0;

            Regex graphicPattern = new Regex(@"(.*)\.(PNG|JPEG)");
            string[] currentFiles = Directory.GetFiles(StorePath);
            foreach(string f in currentFiles) {
                string filename = Path.GetFileName(f);
                Match gMatch = graphicPattern.Match(filename);
                if(gMatch.Success) {
                    string gString = gMatch.Groups[1].Value;
                    Guid g = Guid.Parse(gString);
                    if(!(indexedGuids.Contains(g))) {
                        File.Delete(f);
                        filesDeleted++;
                    }
                }
            }

            log.DebugFormat("Deleted {0} files", filesDeleted);

        }

        public Dictionary<Guid, GraphicResource> LoadAllResources() {
            Dictionary<Guid, GraphicResource> resources = new Dictionary<Guid, GraphicResource>();

            string indexFilename = string.Format("{0}\\{1}", StorePath, INDEX_FILE);
            XElement indexNode = XElement.Load(indexFilename);

            //Get all of the files that are in the index
            foreach(XElement g in indexNode.Elements(GraphicResource.XML_NAME)) {
                GraphicResource res = LoadGraphicResourceFromFile(g);
                resources[res.ID] = res;
            }

            return resources;
        }

        public GraphicResource Convert(GraphicResource res) {
            //Store to a GraphicResourceWrapper and return that
            string filename = string.Format("{0}\\{1}.{2}", StorePath, res.ID, res.ImageType);

            SaveGraphicResourceToFile(res, filename);
            return GraphicResourceWrapper.FromXml(this, res.GetXmlHeader());
        }

        private static void SaveGraphicResourceToFile(GraphicResource res, string filename) {
            File.WriteAllBytes(filename, res.GraphicBytes);
        }

        private GraphicResource LoadGraphicResourceFromFile(XElement header) {
            return GraphicResourceWrapper.FromXml(this, header);
        }

        public byte[] GetBytesForResource(Guid g) {
            string filename = Directory.GetFiles(StorePath, string.Format("{0}.*", g.ToString())).Single();
            return File.ReadAllBytes(filename);
        }

    }
}
